//给定一个包含 n 个整数的数组 nums 和一个目标值 target，判断 nums 中是否存在四个元素 a，b，c 和 d ，使得 a + b + c + d 的值与 target 相等？找出所有满足条件且不重复的四元组。 
//
// 注意： 
//
// 答案中不可以包含重复的四元组。 
//
// 示例： 
//
// 给定数组 nums = [1, 0, -1, 0, -2, 2]，和 target = 0。
//
//满足要求的四元组集合为：
//[
//  [-1,  0, 0, 1],
//  [-2, -1, 1, 2],
//  [-2,  0, 0, 2]
//]
// 
// Related Topics 数组 哈希表 双指针

package com.yun.leetcode.editor.cn;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

// 【18】 四数之和
public class FourSum {
    public static void main(String[] args) {
        Solution solution = new FourSum().new Solution();
        int[] ary = {1,0,-1,0,-2,2};
        List<List<Integer>> lists = solution.fourSum(ary, 0);
        System.out.println(lists);
    }


    //leetcode submit region begin(Prohibit modification and deletion)
    class Solution {
        public List<List<Integer>> fourSum(int[] nums, int target) {
            List<List<Integer>> result = new ArrayList<>();
            Arrays.sort(nums);
            int len = nums.length;
            if (len == 4) {
                if (nums[1] + nums[2] + nums[3] + nums[0] == target) {

                    List<Integer> item = new ArrayList<>();

                    item.add(nums[0]);
                    item.add(nums[1]);
                    item.add(nums[2]);
                    item.add(nums[3]);
                    result.add(item);
                }
                return result;
            }
            for (int i = 0; i < len - 3; i++) {
                if (i > 0 && nums[i] == nums[i - 1]) {
                    continue;
                }
                for (int j = i + 1; j < len - 2; j++) {
                    if (j > i + 1 && nums[j] == nums[j - 1]) {
                        continue;
                    }
                    int left = j + 1;
                    int right = len - 1;
                    while (left < right) {
                        int sum = nums[i] + nums[j] + nums[left] + nums[right];
                        if (target > sum) {
                            left++;
                        } else if (target < sum) {
                            right--;
                        } else {
                            List<Integer> item = new ArrayList<>();

                            item.add(nums[i]);
                            item.add(nums[j]);
                            item.add(nums[left]);
                            item.add(nums[right]);
                            result.add(item);
                            left++;
                            right--;
                            while (left < right && nums[left] == nums[left - 1]) {
                                left++;
                            }
                            while (left < right && nums[right] == nums[right + 1]) {
                                right--;
                            }
                        }
                    }

                }
            }
            return result;
        }
    }
//leetcode submit region end(Prohibit modification and deletion)

}
// Time Limited 模拟两数之和,超时
   /* public List<List<Integer>> fourSum(int[] nums, int target) {
            List<List<Integer>> result = new ArrayList<>();
            Arrays.sort(nums);
            if (nums.length == 4) {
                if (nums[0] + nums[1] + nums[2] + nums[3] == target) {
                    List<Integer> item = new ArrayList<>();

                    item.add(nums[0]);
                    item.add(nums[1]);
                    item.add(nums[2]);
                    item.add(nums[3]);
                    result.add(item);
                }
                return result;
            }
            for (int i = 0; i < nums.length - 3; i++) {
                if (i > 0 && nums[i] == nums[i - 1]) {
                    continue;
                }
                for (int j = i + 1; j < nums.length - 2; j++) {
                    if (j > i + 1 && nums[j] == nums[j - 1]) {
                        continue;
                    }
                    int left = j + 1;
                    int right = nums.length - 1;
                    while (left < right) {
                        System.out.println("i = " + i + "; j = " + j + "; left = " + left + " ; right = " + right);
                        if (target - nums[i] - nums[j] - nums[left] - nums[right] > 0) {
                            left++;

                        } else if (target - nums[i] - nums[j] - nums[left] - nums[right] < 0) {
                            right--;
                        } else {
                            List<Integer> item = new ArrayList<>();

                            item.add(nums[i]);
                            item.add(nums[j]);
                            item.add(nums[left]);
                            item.add(nums[right]);
                            result.add(item);
                            left++;
                            right--;
                            while (left < right && nums[left] == nums[left - 1]) {
                                left++;
                            }
                            while (left < right && nums[right] == nums[right + 1]) {
                                right--;
                            }
                        }
                    }

                }
            }
            return result;
        }*/


/* class Solution {
        public List<List<Integer>> fourSum(int[] nums, int target) {
            Arrays.sort(nums);
            List<List<Integer>> ans = new ArrayList<>();
            int len = nums.length;
            Arrays.sort(nums);

            for (int i = 0; i < len - 3; i++) {
                if (i > 0 && nums[i] == nums[i - 1])
                    continue;
                for (int j = i + 1; j < len - 2; j++) {
                    if (j > i + 1 && nums[j] == nums[j - 1])
                        continue;
                    int left = j + 1;
                    int right = len - 1;

                    while (left < right) {
                        int sum = nums[i] + nums[j] + nums[left] + nums[right];

                        if (sum == target) {
                            ans.add(Arrays.asList(nums[i], nums[j], nums[left], nums[right]));
                            while (left < right && nums[left] == nums[left + 1])
                                left++;
                            while (left < right && nums[right] == nums[right - 1])
                                right--;
                            left++;
                            right--;
                        } else if (sum > target)
                            right--;
                        else if (sum < target)
                            left++;

                    }
                }
            }
            return ans;
        }
    }*/